#pragma once

#include <iostream>
#include <memory>
#include <string>
#include <sstream>
#include <jsoncpp/json/json.h>
#include <jsoncpp/json/writer.h>  
#include <unordered_map>
#include <fstream>

// #define SelfDefine

namespace Protocol{

const std::string HttpSep = "\r\n";
//这个是配置的
const std::string wwwroot = "./wwwroot";
const std::string homepage= "Home.html";
const std::string page404 = "404.html";
const std::string BlankSep = " ";
struct Contentmap{

    static void Init()
    {
        if(_Cont_type.empty())
        {
            std::ifstream ifs("Content-type.conf");
            std::string subfix;
            std::string type;
            while(!ifs.eof())
            {
                ifs>>subfix;
                if(subfix.find(".") == std::string::npos) break;
                ifs>>type;
                _Cont_type[subfix] = type;
            }
            ifs.close();
        }
    }
    static std::string sub_type(const std::string & subfix)
    {
        if(_Cont_type.find(subfix)==_Cont_type.end());
        {
            return "text/html";
        }
        return _Cont_type[subfix];
    }
    static std::unordered_map<std::string,std::string> _Cont_type;
};
std::unordered_map<std::string,std::string> Contentmap:: _Cont_type;

struct Status_code_Desc{
    static void Init()
    {
        if(_code_Desc.empty())
        {
            std::ifstream ifs("status_code.conf");
            if(!ifs.is_open())
            {
                return ;
            }
            std::string code;
            std::string en_desc;
            std::string zh_desc;
            while(!ifs.eof())
            {
                ifs>>code;
                ifs>>en_desc;
                ifs>>zh_desc;
                _code_Desc[code] = en_desc + BlankSep + zh_desc;
            }
        }
    }
    static std::string Code_desc(int code)
    {
        return Code_desc(std::to_string(code));
    }
    static std::string Code_desc(std::string code)
    {
        return _code_Desc[code];
    }
    static std::unordered_map<std::string,std::string> _code_Desc;
};

std::unordered_map<std::string,std::string> Status_code_Desc::_code_Desc;


class HttpRequest{


    std::string GetFileContent(const std::string& path)
    {
        std::fstream fs(path,std::ios::binary | std::ios::in);
        if(!fs.is_open())
        {
            return "";
        }

        fs.seekg(0,fs.end);
        int filesize = fs.tellg();
        fs.seekg(0,fs.beg);
        
        std::string content;
        content.resize(filesize);
        fs.read((char*)content.c_str(),content.size()); 
        fs.close();
        return content;
    }
public:
    HttpRequest()
    :_req_blank(HttpSep)
    ,_path(wwwroot)
    {

    }
    bool Getline(std::string &str,std::string * line)
    {
        auto pos = str.find(_req_blank);
        if(pos == std::string::npos)
            return 0;
        *line = str.substr(0,pos);
        str.erase(0,pos+_req_blank.size());
        return 1;
    }
    bool Deserialize(std::string &request)
    {
        std::string line;
        if(!Getline(request,&line))
            return 0;
        _req_line = line;
        while(1)
        {
            bool ready = Getline(request,&line);
            if(ready && line.empty())
            {
                //这里的解析，在有客服端发来的响应时，需要去header里面，拿出contentlength来解析读取的长度
                //但是也可能发过来的内容长度过长，所以应该是要接受一个套接字，但是那种情况暂时不处理
                _req_content = request;
                break;
            }
            else if(ready && !line.empty())
            {
                _req_header.push_back(line);
            }
            else
            {
                break;
            }
        }
        return 1;
    }
    void ParseReline(){ 
        std::stringstream sstr(_req_line);
        sstr>>_method>>_url>>_http_version;
        if(_url == "/")
        {
            _path += _url+ homepage;
        }
        else
        {
            _path+= _url;
        }
    }

    void ParseSuffix()
    {
        auto pos = _path.rfind(".");
        if(pos ==std::string::npos){
             _subffix =  ".*";return ;
        }
        else _subffix = _path.substr(pos);
    }

    
    std::string GetUrlContent()
    {
        return GetFileContent(_path);
    }

    std::string Get404()
    {
        return GetFileContent(wwwroot + "/" + page404);
    }
    std::string Path()
    {
        return _path;
    }
    void Parse()
    {
        //1.分析请求行
        ParseReline();
        ParseSuffix();
    }
    std::string url()
    {
        return _url;
    }
    std::string Subffix()
    {
        return _subffix;
    }
    void DebugHttp()
    {
        std::cout<<"_req_line:"<<_req_line<<"\n";
        for(auto &line: _req_header)
        {
            std::cout<<">>>>>"<<line<<"\n";
        }
        std::cout<<"req_blank:"<<_req_blank<<"\n";
        std::cout<<"req_content:"<<_req_content<<"\n";

        std::cout<<"method :"<<_method<<"\n";
        std::cout<<"url:"<<_url<<"\n";
        std::cout<<"http_version:"<<_http_version<<"\n";
    }

private:
    //http自动报文 解析
    std::string _req_line;
    std::vector<std::string> _req_header;
    std::string _req_blank; //请求行的空白分隔符
    std::string _req_content;


    //http 解析的内容
    std::string _path;
    std::string _method;
    std::string _url;
    std::string _http_version;
    std::string _subffix;
};




class HttpResponse{
      
    
public:

    HttpResponse()
    :_http_version("Http/1.0")
    ,_status_code(200)
    ,_status_code_desc("OK")
    {   

    }
    void AddHeader(const std::string& header)
    {
        _resp_header.push_back(header);
    }
    void SetCode(int code)
    {
        _status_code = code;
    }
    void SetCode_Desc(const std::string& Code_desc)
    {
        _status_code_desc = Code_desc;
    }
    void make()
    {
        _status_line  = _http_version+ BlankSep +std:: to_string(_status_code ) + BlankSep+ _status_code_desc + HttpSep; 
    }

    void AddContent(const std::string & content)
    {
        _resp_content = content;
    }

    std::string serialize()
    {
        std::string response_string = _status_line;
        for(auto& header:_resp_header)
        {
            response_string+= header;
        }
        response_string += HttpSep;
        response_string += _resp_content;

        return response_string;
    }





private:
    std::string _status_line;
    std::vector<std::string> _resp_header;
    std::string _blank_line;
    std::string _resp_content;//body 
    //
    std::string _http_version;
    int _status_code;
    std::string _status_code_desc;
};


};